#pragma once

#include "Comm.hpp"
#include "Poller.hpp"
#include "TimerWheel.hpp"


class EventLoop
{
private:
    using task_t = std::function<void()>;

    // 执行任务池中所有的任务
    void RunAllTask()
    {
        std::vector<task_t> tasks;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.swap(tasks);  // 保证后来的任务不被阻塞
        }
        int i = 1;
        for (auto& task : tasks)
        {
            task();
            LOG(DEBUG, "Task %d is executed!\n", i++);
        }
        return;
    }

    static int CreateEventFD()
    {
        int efd = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd < 0)
        {
            LOG(FATAL, "eventfd create error, errno: %d -> %s\n", errno, strerror(errno));
            exit(EVENTFD_CREATE_ERROR);
        }
        LOG(DEBUG, "eventfd create success, efd: %d\n", efd);
        return efd;
    }

    void ReadEventFD()
    {
        uint64_t res = 0;
        ssize_t ret = ::read(_event_fd, &res, sizeof res);
        if (ret != sizeof res)
        {
            if (errno == EINTR || errno == EAGAIN) return;
            LOG(FATAL, "eventfd read error, errno: %d -> %s\n", errno, strerror(errno));
            exit(EVENTFD_READ_ERROR);
        }
    }

    void WeakUpEventfd()
    {
        uint64_t val = 1;
        ssize_t ret = ::write(_event_fd, &val, sizeof val);
        if (ret != (sizeof val))
        {
            if (errno == EINTR) return;
            LOG(FATAL, "eventfd write error, errno: %d -> %s\n", errno, strerror(errno));
            exit(EVENTFD_WRITE_ERROR);
        }
        LOG(DEBUG, "eventfd WeakUp\n");
    }

    // 判断当前线程是否是 EventLoop 对应的线程
    bool IsInLoop()
    {
        return _thread_id == std::this_thread::get_id();
    }

public:
    EventLoop()
        : _poller(), 
          _thread_id(std::this_thread::get_id()), 
          _event_fd(CreateEventFD()), 
          _event_channel(std::make_unique<Channel>(_event_fd)), 
          _timer_wheel(this)
    {
        _event_channel->RegisterOperator(
            std::bind(&EventLoop::UpdateEvent, this, _event_channel.get()),
            std::bind(&EventLoop::RemoveEvent, this, _event_channel.get())
        );
        _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventFD, this));
        _event_channel->EnableRead();

        _timer_wheel.Init(std::bind(&EventLoop::UpdateEvent, this, std::placeholders::_1), std::bind(&EventLoop::RemoveEvent, this, std::placeholders::_1));
    }

    void Start()
    {
        while (true)
        {
            // 1、事件监控
            std::vector<Channel*> actives;
            _poller.Poll(&actives);

            // 2、事件处理
            for (auto& channel : actives)
            {
                channel->HandleEvent();
            }

            // 3、执行任务池
            RunAllTask();
        }
    }

    // 先判断当前任务是否在当前线程中：是则执行；不是则压入任务池
    void RunInLoop(const task_t& cb)
    {
        if (IsInLoop())
        {
            cb();
            return;
        }
        LOG(DEBUG, "Does not match the current thread && Presses the task into the task pool!\n");
        return PressInPool(cb);
    }

    // 将操作压入任务池
    void PressInPool(const task_t& cb)
    {
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.push_back(cb);
            LOG(DEBUG, "Task %d is pressed into the task pool!\n", _tasks.size());
        }
        // 唤醒有可能因为 epoll 等待事件而导致的阻塞线程，不能因为监控事件的阻塞导致线程无法执行其他任务，效率低下
        WeakUpEventfd();
    }

    void AssertInLoop() { assert(_thread_id == std::this_thread::get_id()); }

    // 添加/修改 fd 的事件监控
    void UpdateEvent(Channel* channel) { return _poller.UpdateEvent(channel); }

    // 移除 fd 的事件监控
    void RemoveEvent(Channel* channel) { return _poller.RemoveEvent(channel); }


    void TimerAdd(uint64_t id, uint32_t delay, const task_t& cb)
    {
        return _timer_wheel.TimerAdd(id, delay, cb);
    }

    void TimerRefresh(uint64_t id)
    {
        return _timer_wheel.TimerRefresh(id);
    }

    void TimerCancel(uint64_t id)
    {
        return _timer_wheel.TimerCancel(id);
    }

    bool HasTimer(uint64_t id)
    {
        return _timer_wheel.HasTimer(id);
    }

    ~EventLoop()
    {}

private:
    std::thread::id _thread_id;                 // 线程 ID
    Poller _poller;                             // epoll 监控 fd 事件

    int _event_fd;                              // 事件通知，唤醒 IO 事件监控有可能导致的阻塞
    std::unique_ptr<Channel> _event_channel;    // 管理 _event_fd 的事件

    TimerWheel _timer_wheel;                    // 定时器模块

    std::mutex _mutex;                          // 实现任务池的线程安全问题
    std::vector<task_t> _tasks;                 // 任务池
};




void TimerWheel::TimerAdd(uint64_t id, uint32_t delay, const task_t& cb)
{
    LOG(DEBUG, "TimerWheel::TimerAddInLoop\n");
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, delay, cb));
    LOG(DEBUG, "Timer %d: Scheduled task %d is added!\n", _timerfd, id);
}

void TimerWheel::TimerRefresh(uint64_t id)
{
    LOG(DEBUG, "TimerWheel::TimerRefreshInLoop\n");
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop, this, id));
    LOG(TDEBUG, "Timer %d: Scheduled task %d is refreshed!\n", _timerfd, id);
}

void TimerWheel::TimerCancel(uint64_t id)
{
    LOG(DEBUG, "TimerWheel::TimerCancelInLoop\n");
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop, this, id));
    LOG(DEBUG, "Timer %d: Scheduled task %d is cancelled!\n", _timerfd, id);
}